package concurrent;

/**
 * @Description: TODO ThreadLocal 无论是不是静态的都是线程安全的
 * @Author: wzj
 * @Date: 2020/6/10 13:58
 */
/*
为保证多个线程对共享变量的安全访问，可以将类变量放到ThreadLocal类型的对象中，
使变量在每个线程中都有独立拷贝，不会出现一个线程读取变量时而被另一个线程修改的现象。最常见的ThreadLocal使用场景为用来解决数据库连接、Session管理等。
 */
public class ThreadLocalDemo {
    public static void main(String[] args) {
        /*以下几种场景ThreadLocal是安全的*/

        //针对同一个对象，成员实例变量和静态变量都是线程不安全的，ThreadLocal是安全的
//        ThreadLocalRunnable tlr=new ThreadLocalRunnable();
//        new Thread(tlr).start();
//        new Thread(tlr).start();

        //针对不同对象，静态变量都是线程不安全的，成员实例变量和ThreadLocal是安全的，但是对象如果是单例的，那么成员实例变量也是不安全的
        ThreadLocalRunnable tlr=new ThreadLocalRunnable();
        ThreadLocalRunnable tlr1=new ThreadLocalRunnable();
        new Thread(tlr).start();
        new Thread(tlr1).start();

        //不同线程使用同一个的ThreadLocal对象
        ThreadLocal<Integer> threadLocal=new ThreadLocal(){
            @Override
            protected Integer initialValue() {
                return 0;
            }
        };
//        ThreadLocalRunnable1 tlr=new ThreadLocalRunnable1(threadLocal,"同一个threadLocal对象");
//        ThreadLocalRunnable1 tlr1=new ThreadLocalRunnable1(threadLocal,"同一个threadLocal对象");
//        new Thread(tlr).start();
//        new Thread(tlr1).start();

        //不同线程使用不同的ThreadLocal对象
        ThreadLocal<Integer> threadLocal1=new ThreadLocal(){
            @Override
            protected Integer initialValue() {
                return 0;
            }
        };
//        ThreadLocalRunnable1 tlrDif=new ThreadLocalRunnable1(threadLocal,"不同的ThreadLocal对象");
//        ThreadLocalRunnable1 tlrDif1=new ThreadLocalRunnable1(threadLocal1,"不同的ThreadLocal对象");
//        new Thread(tlrDif).start();
//        new Thread(tlrDif1).start();
    }
}

class ThreadLocalRunnable implements Runnable{
    private ThreadLocal<Integer> threadLocal=new ThreadLocal(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };//创建ThreadLocal对象的同时重写initialValue，设置初始值

    private static ThreadLocal<Integer> threadLocalStatic=new ThreadLocal(){
        @Override
        protected Integer initialValue() {
            return 0;
        }
    };//创建ThreadLocal对象的同时重写initialValue，设置初始值

    private int slVar=0;//成员实例变量
    private static int staticVar=0;//成员静态变量

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            int k=threadLocal.get();
            k++;
            threadLocal.set(k);

            k=threadLocalStatic.get();
            k++;
            threadLocalStatic.set(k);

            slVar++;

            staticVar++;

            System.out.println(Thread.currentThread().getName()+" ThreadLocal值为 "+threadLocal.get());
            System.out.println(Thread.currentThread().getName()+" 静态ThreadLocal值为 "+threadLocalStatic.get());
            System.out.println(Thread.currentThread().getName()+" 实例变量值为 "+slVar);
            System.out.println(Thread.currentThread().getName()+" 静态变量值为 "+staticVar);
        }
    }
}

class ThreadLocalRunnable1 implements Runnable{
    private ThreadLocal<Integer> threadLocal;//创建ThreadLocal对象的同时重写initialValue，设置初始值
    private String str;

    public ThreadLocalRunnable1(ThreadLocal<Integer> threadLocal,String str) {
        this.threadLocal = threadLocal;
        this.str = str;
    }

    @Override
    public void run(){
        for(int i=0;i<5;i++){
            int k=threadLocal.get();
            k++;
            threadLocal.set(k);
            System.out.println(str+"        "+Thread.currentThread().getName()+" ThreadLocal值为 "+threadLocal.get());
        }
    }
}